﻿using System;
using System.ComponentModel;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Drawing;
using System.Text;
using System.Configuration;

using BizElements.BusinessLayer;

namespace BizElements.Web
{
    /// <summary>
    /// <see cref="DataGrid"/> template which displays and edits the value of a bound field in a <see cref="BoundAutoComplete"/> control.
    /// </summary>
    public class BoundAutoCompleteTemplate : BoundTemplateBase, ISearchClient
    {
        #region CTor.

        /// <summary>
        /// Initializes a new instance of the <b>BoundAutoCompleteTemplate</b> class.
        /// </summary>
        public BoundAutoCompleteTemplate()
        {
        }

        /// <summary>
        /// Initializes a new instance of the <b>BoundAutoCompleteTemplate</b> class.
        /// </summary>
        /// <param name="field"><see cref="IBindableField"/> that contains a reference and meta-data for a bound business class property.</param>
        /// <param name="formatter">The <see cref="IMessageFormatter"/> object used to format bound values.</param>
        public BoundAutoCompleteTemplate(IBindableField field, IMessageFormatter formatter)
            : base(field, formatter)
        {
        }

        #endregion

        #region Instantiate and bind.

        /// <summary>
        /// Defines the <see cref="DataGrid"/> that child controls and the template belong to.
        /// </summary>
        /// <param name="container">The <b>TableCell</b> which contains the <b>BoundAutoComplete</b> controls instantiated by this template.</param>
        public override void InstantiateIn(Control container)
        {
            BoundAutoComplete lookup = new BoundAutoComplete();
            lookup.DataBinding += new EventHandler(this.BindDisplayValue);
            if (this.SkinID != null)
            {
                lookup.SkinID = this.SkinID;
                Page page = HttpContext.Current.Handler as Page;
                if (page != null)
                    lookup.ApplyStyleSheetSkin(page);
            }

            container.Controls.Add(lookup);
        }

        private void BindDisplayValue(object sender, EventArgs e)
        {
            string displayExpression = this.BoundField.BindingName;
            if (this.BoundField.SatelliteFields != null && this.BoundField.SatelliteFields.Length > 0)
                displayExpression = this.BoundField.SatelliteFields[0];

            BoundAutoComplete lookup = (BoundAutoComplete)sender;
            ApplyStyle(lookup);

            lookup.AccessMode = this.AccessMode;
            SetControlProperties(lookup);

            DataGridItem currentItem = (DataGridItem)lookup.NamingContainer;
            object keyValue = DataBinder.Eval(currentItem.DataItem, this.BoundField.BindingName);
            object displayValue = DataBinder.Eval(currentItem.DataItem, displayExpression);
            lookup.SelectedValue = this.Formatter.Format(keyValue);
            lookup.Text = this.Formatter.Format(displayValue);
        }

        private void SetControlProperties(BoundAutoComplete lookup)
        {
            lookup.SearchProviderKey = this.SearchProviderKey;
            if (!string.IsNullOrEmpty(this.ReadOnlyCss))
                lookup.ReadOnlyCssClass = this.ReadOnlyCss;
            if (!string.IsNullOrEmpty(this.ServicePath))
                lookup.ServicePath = this.ServicePath;
            if (!string.IsNullOrEmpty(this.GetCompletionListServiceMethod))
                lookup.GetCompletionListServiceMethod = this.GetCompletionListServiceMethod;
            if (!string.IsNullOrEmpty(this.GetKeyValueServiceMethod))
                lookup.GetKeyValueServiceMethod = this.GetKeyValueServiceMethod;
            if (!string.IsNullOrEmpty(this.GetKeyAndDisplayValueServiceMethod))
                lookup.GetKeyAndDisplayValueServiceMethod = this.GetKeyAndDisplayValueServiceMethod;
            if (this.MinimumPrefixLength.HasValue)
                lookup.MinimumPrefixLength = this.MinimumPrefixLength.Value;
            if (this.CompletionSetCount.HasValue)
                lookup.CompletionSetCount = this.CompletionSetCount.Value;
            if (!string.IsNullOrEmpty(this.CompletionListCssClass))
                lookup.CompletionListCssClass = this.CompletionListCssClass;
            if (!string.IsNullOrEmpty(this.CompletionListItemCssClass))
                lookup.CompletionListItemCssClass = this.CompletionListItemCssClass;
            if (!string.IsNullOrEmpty(this.CompletionListHighlightedItemCssClass))
                lookup.CompletionListHighlightedItemCssClass = this.CompletionListHighlightedItemCssClass;
            if (this.Columns.HasValue)
                lookup.Columns = this.Columns.Value;
            if (this.ClearImageVisible.HasValue)
                lookup.ClearImageVisible = this.ClearImageVisible.Value;
            if (!string.IsNullOrEmpty(this.ClearImageUrl))
                lookup.ClearImageUrl = this.ClearImageUrl;
            if (!string.IsNullOrEmpty(this.ClearImageCssClass))
                lookup.ClearImageCssClass = this.ClearImageCssClass;
        }

        #endregion

        #region ISearchClient.

        /// <summary>
        /// Not supported. Returns <b>null</b>.
        /// </summary>
        IWebCommand ISearchClient.CreateAcceptCommand(bool calledFromPopupWindow, string text, string[] requiredParameters)
        {
            return null;
        }

        /// <summary>
        /// Not supported. Returns <b>null</b>.
        /// </summary>
        IWebCommand ISearchClient.CreateCancelCommand(bool calledFromPopupWindow, string text)
        {
            return null;
        }

        /// <summary>
        /// Gets or sets the key under which the search provider is registered in <see cref="SearchProviderRegistry"/>.
        /// </summary>
        public string SearchProviderKey { get; set; }

        #endregion

        #region Properties.

        /// <summary>
        /// Gets or sets the path to the web service that the control will pull the word completions from and fetch key values.
        /// </summary>
        /// <remarks>The service must expose the methods defined by <see cref="GetCompletionListServiceMethod"/> 
        /// and <see cref="GetKeyValueServiceMethod"/> properties.</remarks>
        public string ServicePath { get; set; }

        /// <summary>
        /// Gets or sets the web service method to be called when a user types some text and which returns word completions.
        /// </summary>
        /// <remarks>The signature of the Web method must match the following:
        /// <code>public string[] GetCompletionList(string prefixText, int count)</code>
        /// Note that you can replace "GetCompletionList" with a name of your choice, but the return type and parameter name 
        /// and type must exactly match, including case.
        /// </remarks>
        public string GetCompletionListServiceMethod { get; set; }

        /// <summary>
        /// Gets or sets the web service method to be called when a user selects an item form the flyout list/menu and which returns a key value that matches entered/selected text/display value.
        /// </summary>
        /// <remarks>The signature of this method must match the following:
        /// <code>public string GetKeyValue(string prefixText, string contextKey)</code>
        /// Note that you can replace "GetKeyValue" with a name of your choice, but the return type and parameter name 
        /// and type must exactly match, including case.
        /// </remarks>
        public string GetKeyValueServiceMethod { get; set; }

        /// <summary>
        /// Gets or sets optional web service method to be called when a user types in a value prefix but doesn't wait for flyout list/menu to be populated. The method returns key and display value that match entered prefix (array of string that contains two items).
        /// </summary>
        /// <remarks>The signature of this method must match the following:
        /// <code>public string[] GetKeyAndDisplayValue(string prefixText, string contextKey)</code>
        /// Note that you can replace "GetKeyAndDisplayValue" with a name of your choice, but the return type and parameter names 
        /// and types must exactly match, including case.
        /// </remarks>
        public string GetKeyAndDisplayValueServiceMethod { get; set; }

        /// <summary>
        /// Gets or sets minimum number of characters that must be entered before getting suggestions from the web service.
        /// </summary>
        public int? MinimumPrefixLength { get; set; }

        /// <summary>
        /// Gets or sets the number of suggestions to be retrieved from the web service.
        /// </summary>
        public int? CompletionSetCount { get; set; }

        /// <summary>
        /// Gets or sets CSS Class that will be used to style the completion list flyout.
        /// </summary>
        public string CompletionListCssClass { get; set; }

        /// <summary>
        /// Gets or sets CSS Class that will be used to style an item in the AutoComplete list flyout.
        /// </summary>
        public string CompletionListItemCssClass { get; set; }

        /// <summary>
        /// Gets or sets CSS Class that will be used to style a highlighted item in the AutoComplete list flyout.
        /// </summary>
        public string CompletionListHighlightedItemCssClass { get; set; }

        /// <summary>
        /// Gets or sets the display width of the text box in characters.
        /// </summary>
        /// <value>The display width, in characters, of the text box. The default is 0, which indicates that the property is not set.</value>
        public int? Columns { get; set; }

        /// <summary>
        /// Gets or sets a value that indicates whether the clear image is visible.
        /// </summary>
        public bool? ClearImageVisible { get; set; }

        /// <summary>
        /// Gets or sets the URL of the clear button image.
        /// </summary>
        public string ClearImageUrl { get; set; }

        /// <summary>
        /// Gets or sets the Cascading Style Sheet (CSS) class applied to clear image.
        /// </summary>
        public string ClearImageCssClass { get; set; }

        #endregion
    }
}